package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/cn-ygf/go-admin/internal/modular/system/model"
	"github.com/cn-ygf/go-admin/pkg/config"
	"github.com/cn-ygf/go-admin/pkg/rand"
	"github.com/cn-ygf/go-admin/pkg/redis"
	"github.com/kataras/iris/v12"
	"golang.org/x/crypto/bcrypt"
	"strings"
)

var (
	LoginService     = new(loginService)
	LoginError       = errors.New("登录失败，用户名或密码错误")
	LoginStatusError = errors.New("登录失败，账号被停用")
	TokenError       = errors.New("令牌验证失败")
	UserStatusError  = errors.New("账号状态异常")
)

const (
	TokenPrefix = "go_admin_token_"
)

// loginService 登录相关业务
type loginService struct {
}

// Login 用户登录
// username 用户名
// password 密码
func (s loginService) Login(username, password string) (*model.SysUser, error) {
	user, err := UserService.GetByUserName(username)
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, LoginError
	}
	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, LoginError
	}
	if user.Status != "0" {
		return nil, LoginStatusError
	}
	return user, nil
}

// GenerateToken 根据用户生成token
func (s loginService) GenerateToken(user *model.SysUser) (string, error) {
	expireAt := config.GetInt("server.tokenExpires")
	if expireAt < 1 {
		expireAt = 7200
	}
	token := rand.S(32)
	key := fmt.Sprintf("%s%s", TokenPrefix, token)
	user.Password = ""
	buf, err := json.Marshal(user)
	if err != nil {
		systemLog.Errorln(err.Error())
		return "", ServerError
	}
	if err = redis.Set(key, buf); err != nil {
		systemLog.Errorln(err.Error())
		return "", RedisError
	}
	redis.Expire(key, expireAt)
	return token, nil
}

func (s loginService) ClearToken(c iris.Context) {
	token := c.GetHeader("Authorization")
	if token != "" {
		token = strings.Replace(token, "Bearer ", "", 1)
		key := fmt.Sprintf("%s%s", TokenPrefix, token)
		err := redis.Del(key)
		if err != nil {
			systemLog.Errorln(err.Error())
		}
		return
	}
}

// VerifyToken 验证token
func (s loginService) VerifyToken(token string) (*model.SysUser, error) {
	expireAt := config.GetInt("server.tokenExpires")
	if expireAt < 1 {
		expireAt = 7200
	}
	key := fmt.Sprintf("%s%s", TokenPrefix, token)
	buf, err := redis.GetBytes(key)
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, RedisError
	}
	redis.Expire(key, expireAt)
	u := new(model.SysUser)
	if err = json.Unmarshal(buf, u); err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	user, err := UserService.GetByID(u.UserID)
	if err != nil {
		systemLog.Errorln(err.Error())
		return nil, ServerError
	}
	if user.Status != "0" {
		return nil, UserStatusError
	}
	return user, nil
}
